#include"EventLoopThread.h"

using namespace tmms::network;

EventLoopThread::EventLoopThread():thread_([this](){
    StartEventLoop(); //线程函数，//构造的时候直接start（） APT的特性
})
{

}


EventLoopThread::~EventLoopThread()
{
    Run(); //TODO 为何析构的时候先让他跑起来？  不然他就会一直等待
    //应对线程尚未启动完成就销毁的场景。Run()中的notify_all会唤醒可能阻塞在condition_.wait的线程，避免死锁。这种防御式编程很有必要。
    if(loop_)
    {
        loop_->Quit();//事件循环退出来，然后我们的线程就会自动退出来了
    }
    if(thread_.joinable()){
        thread_.join();
    }
}

void EventLoopThread::Run() //这个是由创建EventLoopThread的线程调用的EventLoopThread.Run()，
{
    std::call_once(once_,[this](){
        {
            std::lock_guard<std::mutex> lk(lock_);
            running_ =true;
            condition_.notify_all();//就是wakeall（）
        }
        //这个的作用是做同步用的
        auto f = promise_loop_.get_future();//这个会一直等待返回一个值
        f.get(); //​​future:阻塞当前线程​​，直到promise设置值后才继续执行
    }); //这个callonce保证只用调用一次
}


EventLoop * EventLoopThread::loop() const 
{
    return loop_;
}

void EventLoopThread::StartEventLoop() //需要跟Run（）函数做一个同步
{ // 把线程的声明周期与之同步
    EventLoop loop; //定义局部变量才可以保证两者的声明周期一致啊
    std::unique_lock<std::mutex> lk(lock_); //lk不是一个函数，一个对象，括号里面为他的构造函数的参数，构造时立即锁定​​互斥锁
    condition_.wait(lk,[this](){return running_;}); //等待主线程调用Run()
    /*第二个参数为真的时候，这个wait才会退出,用于解决虚假唤醒,相当于while (![this](){ return running_; }) {
        condition_.wait(lk);
    }*/
    loop_ = &loop; 
    promise_loop_.set_value(1);//设置一个值​​（通过set_value），并通知等待该值的线程。
    //这个Loop就是事件循环开始了，所以上面的事情：需要等待Run()函数的指令才会开始Loop（），所以才会有上面的那些
    loop.Loop(); //这个是死循环，等待fd就绪,这里就是开始把事件循环跑起来
    loop_ = nullptr;
}

std::thread& EventLoopThread::Thread()
{
    return thread_;
}


